package wsi.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JFileChooser;

import org.rygh.core.model.notice.INotifiable;
import org.rygh.core.model.notice.Notice;
import org.rygh.core.model.notice.NotificationCenter;
import org.rygh.core.util.UIo;
import org.rygh.gui.model.callback.Callback;
import org.rygh.gui.model.callback.Returnback;
import org.rygh.gui.model.callback.Simpleback;
import org.rygh.gui.swing.USwing;
import org.rygh.gui.swing.common.text.STextPresenter;
import org.rygh.gui.swing.common.view.SProgressGlass;
import org.rygh.gui.swing.common.window.xml.SXmlPresenter;
import org.rygh.gui.swing.menu.SMenu;
import org.rygh.gui.swing.menu.SMenuItem;
import org.rygh.gui.swing.presenter.SwingPresenter;
import org.rygh.semantic.func.PathFunctionalityChecker;
import org.rygh.semantic.gui.swing.database.DBPresenter;
import org.rygh.semantic.gui.swing.pref.SPrefWindow;
import org.rygh.semantic.gui.swing.query.QueryPresenter;
import org.rygh.semantic.jena.SDataAccess;

import wsi.exp.Exp1SelectedTree;
import wsi.exp.Exp2TreeToEntity;
import wsi.exp.Exp4WebCallRatio;
import wsi.exp.Exp6Dependency;
import wsi.exp.exp3.Exp3PathMatchByPair;
import wsi.exp.exp3.Exp3PathMatchByPred;
import wsi.exp.exp5.Exp5EntityFusion;
import wsi.function.Function;
import wsi.gui.detector.DetectorPresenter;
import wsi.gui.function.FunctionPresenter;
import wsi.gui.function.select.FunctionSelectPresenter;
import wsi.gui.predpath.PredicatePathPresenter;
import wsi.gui.predpath.PredicatePathTime;
import wsi.gui.pref.PrefWindow;
import wsi.gui.tool.DBInjector;
import wsi.gui.tool.DBSaver;
import wsi.gui.tool.TempTask;
import app.tool.resetFunctions;

public class AppPresenter extends SwingPresenter implements INotifiable {

	public interface Display extends SwingPresenter.Display {
		SMenu getFunctionMenu();

		void setHtml(String html);

		void setXml(String xml);

		void updateFunctionMenu();
	}

	private PrefWindow prefWindow;
	private SPrefWindow sPrefWindow;

	private final JFileChooser fileChooser = new JFileChooser();
	private FunctionSelectPresenter functionSelectPresenter;
	private FunctionPresenter functionPresenter;
	private DBPresenter dbPresenter;
	private DetectorPresenter detectPresenter;
	private QueryPresenter queryPresenter;
	private PredicatePathPresenter predicatePathPresenter;
	private SXmlPresenter xmlPresenter;
	private STextPresenter textPresenter;

	private String content;

	public AppPresenter() {
		display = new AppWindow(this);

		init();
	}

	public void about() {
		getWindow().message("Actively Built Period: Spring to Fall 2013.");
	}

	public void checkPredicatePathTime() {
		SProgressGlass<String> progress = getWindow().progress("Checking...",
				new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				PathFunctionalityChecker checker = new PathFunctionalityChecker();
				checker.check();

				String res = checker.toHtmlTable().toSimpleString();
				UIo.saveFile(new File("e:/a.html"), res);

				return res;
			}
		});
		progress.run();
	}

	public void clearDatabase() {
		getWindow().question("Clear Database?", new Simpleback() {

			@Override
			public void call() {
				USwing.invokeLater(new Simpleback() {

					@Override
					public void call() {
						SDataAccess.clear();
					}
				}, getWindow().getTitle(), "Database Cleared.");
			}
		});
	}

	@Override
	public void close() {
		super.close();
		Property.shared().save();
	}

	private void displayFunction(Function value) {
		if (functionPresenter == null)
			functionPresenter = new FunctionPresenter(this);

		functionPresenter.load(value);
		functionPresenter.display();
	}

	public void experiemnt1() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 1...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp1SelectedTree exp = new Exp1SelectedTree();
				exp.compute();

				return exp.save();
			}
		});
		progress.run();
	}

	public void experiemnt2() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 2B...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp2TreeToEntity exp = new Exp2TreeToEntity();
				exp.compute();

				return exp.save();
			}
		});
		progress.run();
	}

	public void experiemnt2b() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 2B...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp5EntityFusion exp = new Exp5EntityFusion();
				exp.compute();

				return exp.save();
			}
		});
		progress.run();
	}

	public void experiemnt3Pair() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 3 (by pair)...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp3PathMatchByPair exp = new Exp3PathMatchByPair();
				exp.compute();
				return exp.save();
			}
		});
		progress.run();
	}

	public void experiemnt3Predicate() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 3 (by predicate)...",
				new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp3PathMatchByPred exp = new Exp3PathMatchByPred();
				exp.compute();
				return exp.save();
			}
		});
		progress.run();
	}

	public void experiemnt4() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 4...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp4WebCallRatio exp4 = new Exp4WebCallRatio();
				exp4.compute();
				return exp4.save();
			}
		});
		progress.run();
	}

	public void experiemnt6() {
		SProgressGlass<String> progress = getWindow().progress(
				"Running experiment 6...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				Exp6Dependency exp6 = new Exp6Dependency();
				exp6.compute();
				return exp6.save();
			}
		});
		progress.run();
	}

	private void init() {
		updateFunctionMenu();

		NotificationCenter.shared().register(
				FunctionSelectPresenter.EVENT_REFRESH_FUNCTIONS, this);
	}

	public void inject() {
		selectFunction(new Callback<Function>() {
			@Override
			public void call(final Function function) {
				if (function == null)
					return;

				inject(function);
			}

		});
	}

	private void inject(Function function) {
		DBInjector injector = new DBInjector(this);
		injector.inject(function);
	}

	public void jenaPreferences() {
		if (sPrefWindow == null)
			sPrefWindow = new SPrefWindow();

		sPrefWindow.display();
	}

	public void launch() {
		resetParameters();

		selectFunction(new Callback<Function>() {

			@Override
			public void call(Function value) {
				if (value == null)
					return;

				displayFunction(value);
				updateFunctionMenu();
			}

		});
	}

	public void mergePredicatePath() {
		if (predicatePathPresenter == null)
			predicatePathPresenter = new PredicatePathPresenter();

		predicatePathPresenter.display();
	}

	public void newText() {
		if (textPresenter == null)
			textPresenter = new STextPresenter();

		textPresenter.display();
	}

	@Override
	public void notify(Notice notice) {
		if (notice.getName().equals(
				FunctionSelectPresenter.EVENT_REFRESH_FUNCTIONS))
			updateFunctionMenu();
	}

	public void preferences() {
		if (prefWindow == null)
			prefWindow = new PrefWindow();

		prefWindow.display();
	}

	public void prepareInputs() {
		if (detectPresenter == null)
			detectPresenter = new DetectorPresenter();

		detectPresenter.display();
	}

	public void query() {
		if (queryPresenter == null)
			queryPresenter = new QueryPresenter();

		queryPresenter.display();
	}

	public void resetParameters() {

		USwing.invokeLater(new Simpleback() {

			@Override
			public void call() {
				resetFunctions.modify(Function.SKIP_RESET_ARRAY);

			}
		}, null, "System", "Resetting parameters execution finished.");

	}

	public void saveDatabase() {
		selectFunction(new Callback<Function>() {

			@Override
			public void call(Function function) {
				if (function == null)
					return;

				DBSaver saver = new DBSaver();
				saver.save(function);
			}
		});
	}

	public void saveML() {
		if (content == null) {
			getWindow().message("No content to save.");
			return;
		}

		int ret = fileChooser.showSaveDialog(getWindow());

		if (ret == JFileChooser.APPROVE_OPTION) {
			File file = fileChooser.getSelectedFile();
			UIo.saveFile(file, content);
		}
	}

	private void selectFunction(Callback<Function> callback) {
		if (functionSelectPresenter == null)
			functionSelectPresenter = new FunctionSelectPresenter();

		functionSelectPresenter.display();
		functionSelectPresenter.setCallback(callback);
	}

	public void setML(String content) {
		final Display d = (Display) display;
		this.content = content;

		if (content == null)
			d.setHtml("null");
		else if (content.startsWith("<?xml "))
			d.setXml(content);
		else
			d.setHtml(content);
	}

	public void tempTask() {
		SProgressGlass<String> progress = getWindow().progress(
				"Temporary task running...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				return TempTask.run();
			}
		});
		progress.run();
	}

	public void updateFunctionMenu() {
		final Display d = (Display) display;

		d.updateFunctionMenu();

		for (int i = 0; i < d.getFunctionMenu().getItemCount(); i++) {
			final SMenuItem item = (SMenuItem) d.getFunctionMenu().getItem(i);

			item.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					Function function = (Function) item.getValue();
					Property.shared().recordFunction(function);

					displayFunction(function);
					updateFunctionMenu();
				}
			});
		}
	}

	public void viewDatabase() {
		if (dbPresenter == null)
			dbPresenter = new DBPresenter();

		dbPresenter.refresh();
		dbPresenter.display();
	}

	public void viewPredicatePathTime() {
		SProgressGlass<String> progress = getWindow().progress(
				"Please wait...", new Callback<String>() {
					@Override
					public void call(String value) {
						setML(value);
					}
				});
		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				PredicatePathTime time = new PredicatePathTime();
				time.load();
				String result = time.toHtmlString();

				UIo.saveFile(new File("e:/a.html"), result);
				return result;
			}
		});
		progress.run();

	}

	public void viewXml() {
		if (xmlPresenter == null)
			xmlPresenter = new SXmlPresenter();

		xmlPresenter.display();
	}
}
